package com.appstore.common;

import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClient;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.model.GetObjectRequest;
import com.aliyun.oss.model.OSSObject;
import com.aliyun.oss.model.ObjectMetadata;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

@Slf4j
public class AliOSSUtils {
    private String endpoint = "https://oss-cn-beijing.aliyuncs.com";
    private String accessKeyId = "LTAI5tFbdefjTForgXaLDZMz";
    private String accessKeySecret = "VNrOEtX3oXVPQSTmulDmtxNrmaeiu4";
    private String bucketName = "myohap";


    /**
     *从OSS下载软件
     * @param objectKey 路径
     * @param response
     */
    public void downLoad(String objectKey, HttpServletResponse response) {
        log.info("AliOSSUtils.downLoad start. ObjectKey: {}", objectKey);

        // 初始化 OSS 客户端
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);

        try {
            // 检查文件是否存在
            if (!ossClient.doesObjectExist(bucketName, objectKey)) {
                log.error("文件不存在: {}", objectKey);
                response.setStatus(HttpServletResponse.SC_NOT_FOUND);
                return;
            }

            // 获取文件元数据
            ObjectMetadata objectMetadata = ossClient.getObjectMetadata(new GetObjectRequest(bucketName, objectKey));
            String fileName = objectMetadata.getUserMetadata().get("fileName");
            if (fileName == null) {
                fileName = objectKey.substring(objectKey.lastIndexOf('/') + 1);
            }

            // 设置响应头
            response.setContentType(objectMetadata.getContentType());
            response.setHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\"");
            response.setContentLengthLong(objectMetadata.getContentLength());

            // 获取文件输入流并写入响应
            OSSObject ossObject = ossClient.getObject(new GetObjectRequest(bucketName, objectKey));
            InputStream ossInputStream = ossObject.getObjectContent();
            BufferedInputStream bis = new BufferedInputStream(ossInputStream);
            OutputStream os = response.getOutputStream();
            byte[] buffer = new byte[1024];
            int bytesRead;
            while ((bytesRead = bis.read(buffer)) != -1) {
                os.write(buffer, 0, bytesRead);
            }
            os.flush();
        } catch (IOException e) {
            log.error("下载文件失败: {}", objectKey, e);
            response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
        } finally {
            ossClient.shutdown();
        }

        log.info("AliOSSUtils.downLoad end");
    }


    /**
     * 上传文件到OSS
     * params: multipartFile: MultipartFile 上传文件
     *         fileClass: String 文件所属类别 ['avatar', 'images', 'software']
     * return: 上传文件的url
     */
    public String upload(MultipartFile multipartFile, String fileClass) throws IOException {
        log.info("AliOSSUtils.upload start");
        //获取上传文件的输入流
        InputStream inputStream = multipartFile.getInputStream();
        // 重命名文件 避免文件覆盖
        String fileName = fileClass + '/' + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd-HH-mm-ss")) + multipartFile.getOriginalFilename();
        // 上传文件到OSS
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
        ossClient.putObject(bucketName, fileName, inputStream);
        // 生成文件访问路径
        String url = endpoint.split("//")[0] + "//" + bucketName + "." + endpoint.split("//")[1] + "/" + fileName;
        // 关闭ossClient
        ossClient.shutdown();
        log.info("AliOSSUtils.upload end");
        // 返回文件访问路径
        return url;
    }

    /**
     * 上传多个文件到OSS 多线程 超时控制
     * params: files 上传文件列表 List::MultipartFile
     *         fileClasses 所有上传文件所属的类别列表 List::String
     * return: 上传文件的url列表 List::String
     */
    public List<String> uploadFiles(List<MultipartFile> files, List<String> fileClasses) throws Exception {
        log.info("AliOSSUtils.uploadFiles start");
        // 异常自处理
        // 线程安全的列表存储上传文件的访问URL
        List<String> urls = Collections.synchronizedList(new ArrayList<>());
        // 创建OSS客户端实例
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
        // 创建固定大小的线程池，线程数量可配置
        ExecutorService executor = Executors.newFixedThreadPool(5);
        List<Future<?>> futures = new ArrayList<>();
        long timeout = 10; // 设置超时时间（秒）

        try {
            // 遍历所有文件并提交上传任务
            for (int i = 0; i < files.size(); i++) {
                MultipartFile file = files.get(i);
                String fileClass = fileClasses.get(i);
                if (!file.isEmpty()) { // 忽略空文件
                    Future<?> future = executor.submit(() -> {
                        try {
                            // 获取文件输入流
                            InputStream inputStream = file.getInputStream();
                            // 生成唯一文件名，包含类别信息，避免覆盖
                            String fileName = fileClass + "/" + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd-HH-mm-ss")) + file.getOriginalFilename();
                            // 上传文件到OSS
                            ossClient.putObject(bucketName, fileName, inputStream);
                            // 生成访问URL
                            String url = endpoint.split("//")[0] + "//" + bucketName + "." + endpoint.split("//")[1] + "/" + fileName;
                            // 将URL添加到结果列表
                            urls.add(url);
                        } catch (IOException e) {
                            // 异常处理
                            log.error("上传文件异常, 文件名为:" + file.getOriginalFilename() + "\n" +
                                    "异常信息为: " + e.getMessage());
                            throw new RuntimeException(e);
                        }
                    });
                    // 保存任务的Future对象，便于后续等待完成
                    futures.add(future);
                }
            }

            // 等待所有任务完成，超时则抛出异常
            for (Future<?> future : futures) {
                try {
                    future.get(timeout, TimeUnit.SECONDS);
                } catch (Exception e) {
//                    e.printStackTrace(); // 超时 抛出异常
                    log.error("上传文件超时，请重新尝试");
                    throw new Exception(e);
                }
            }
        } finally {
            // 关闭线程池
            executor.shutdown();
            // 关闭OSS客户端
            ossClient.shutdown();
        }
        // 返回所有上传文件的URL列表
        log.info("AliOSSUtils.uploadFiles end");
        return urls;
    }


}
